// 像素化处理工具函数
// src/utils/pixelator.ts

// import { BrowserCompatibilityError, ImageProcessError } from './errorTypes';
import { AppError, BrowserCompatibilityError/*, ImageLoadError*/, ImageProcessError } from './errorTypes';

// 在 pixelator.ts 文件顶部添加 Bayer 矩阵定义
// 8x8 Bayer 矩阵，用于有序抖动
const BAYER_MATRIX_8X8 = [
  [0, 32, 8, 40, 2, 34, 10, 42],
  [48, 16, 56, 24, 50, 18, 58, 26],
  [12, 44, 4, 36, 14, 46, 6, 38],
  [60, 28, 52, 20, 62, 30, 54, 22],
  [3, 35, 11, 43, 1, 33, 9, 41],
  [51, 19, 59, 27, 49, 17, 57, 25],
  [15, 47, 7, 39, 13, 45, 5, 37],
  [63, 31, 55, 23, 61, 29, 53, 21]
];

export interface PixelationParams {
  pixelSize: number;
  colorDepth: number;
  useDithering: boolean;
}

export interface Palette {
  name: string;
  colors: string[];
}

// 预设调色板
export const PRESET_PALETTES: Palette[] = [
  {
    name: 'Game Boy',
    colors: ['#0f380f', '#306230', '#8bac0f', '#9bbc0f']
  },
  {
    name: 'NES',
    colors: ['#000000', '#555555', '#aaaaaa', '#ffffff', '#ff0000', '#00ff00', '#0000ff', '#ffff00']
  },
  {
    name: 'CGA',
    colors: ['#000000', '#5555ff', '#55ff55', '#55ffff', '#ff5555', '#ff55ff', '#ffff55', '#ffffff']
  },
  {
    name: 'Mono (1-bit)',
    colors: ['#000000', '#ffffff']
  }
];

/**
 * 将图像数据像素化
 */
export async function pixelateImage(
  imageUrl: string,
  params: PixelationParams,
  palette?: Palette
): Promise<string> {

  // 检查浏览器兼容性
  if (!window.HTMLCanvasElement) {
    throw new BrowserCompatibilityError('Canvas');
  }

  return new Promise((resolve, reject) => {
    const img = new Image();
    // 移除 crossOrigin 设置，避免跨域问题
    // img.crossOrigin = 'Anonymous';
    img.onload = () => {
      try {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        if (!ctx) {
          reject(new Error('无法获取canvas上下文'));
          return;
        }

        // 设置canvas尺寸
        canvas.width = img.width;
        canvas.height = img.height;

        // 绘制原始图像
        ctx.drawImage(img, 0, 0);

        // 获取图像数据
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        const data = imageData.data;

        // 应用像素化效果
        const processedData = applyPixelationEffect(data, canvas.width, canvas.height, params, palette);

        // 将处理后的数据放回canvas
        const imageDataObj = ctx.createImageData(canvas.width, canvas.height);
        imageDataObj.data.set(processedData);
        ctx.putImageData(imageDataObj, 0, 0);

        // 返回DataURL
        resolve(canvas.toDataURL('image/png'));
      } catch (error) {
        // reject(error);
        if (error instanceof AppError) {
          reject(error);
        } else {
          reject(new ImageProcessError(
            error instanceof Error ? error.message : 'Unknown processing error'
          ));
        }
      }
    };
    img.onerror = () => reject(new Error('图片加载失败，可能已损坏或格式不支持'));
    img.src = imageUrl;
  });
}

// /**
//  * 应用像素化效果的核心算法
//  */
// function applyPixelationEffect(
//   data: Uint8ClampedArray,
//   width: number,
//   height: number,
//   params: PixelationParams,
//   palette?: Palette
// ): Uint8ClampedArray {
//   const { pixelSize, colorDepth } = params;
//   const output = new Uint8ClampedArray(data.length);

//   for (let y = 0; y < height; y += pixelSize) {
//     for (let x = 0; x < width; x += pixelSize) {
//       // 获取当前像素块的平均颜色
//       const avgColor = getBlockAverageColor(data, x, y, pixelSize, width, height);

//       // 应用颜色深度限制
//       const limitedColor = limitColorDepth(avgColor, colorDepth);

//       // 应用调色板（如果指定）
//       const finalColor = palette ? applyPalette(limitedColor, palette.colors) : limitedColor;

//       // 填充整个像素块
//       fillBlock(output, x, y, pixelSize, width, height, finalColor);
//     }
//   }

//   return output;
// }

/**
 * 获取像素块的平均颜色
 */
function getBlockAverageColor(
  data: Uint8ClampedArray,
  startX: number,
  startY: number,
  size: number,
  width: number,
  height: number
): { r: number; g: number; b: number; a: number } {
  let r = 0, g = 0, b = 0, a = 0;
  let count = 0;

  for (let y = startY; y < startY + size && y < height; y++) {
    for (let x = startX; x < startX + size && x < width; x++) {
      const index = (y * width + x) * 4;
      r += data[index];
      g += data[index + 1];
      b += data[index + 2];
      a += data[index + 3];
      count++;
    }
  }

  return {
    r: Math.round(r / count),
    g: Math.round(g / count),
    b: Math.round(b / count),
    a: Math.round(a / count)
  };
}

/**
 * 限制颜色深度
 */
export function limitColorDepth(color: { r: number; g: number; b: number }, depth: number): { r: number; g: number; b: number; a: number } {
  const levels = Math.pow(2, depth);
  const step = 256 / levels;

  // 确保颜色值在0-255范围内
  const clamp = (value: number) => Math.min(255, Math.max(0, Math.round(value / step) * step));

  return {
    r: clamp(color.r),
    g: clamp(color.g),
    b: clamp(color.b),
    a: 255 // 保持完全不透明
  };
}

/**
 * 应用调色板
 */
export function applyPalette(color: { r: number; g: number; b: number }, paletteColors: string[]): { r: number; g: number; b: number; a: number } {
  let minDistance = Infinity;
  let bestColor = { r: color.r, g: color.g, b: color.b };

  for (const hexColor of paletteColors) {
    const rgb = hexToRgb(hexColor);
    if (!rgb) continue;

    const distance = colorDistance(color, rgb);
    if (distance < minDistance) {
      minDistance = distance;
      bestColor = rgb;
    }
  }

  return { ...bestColor, a: 255 }; // 保持完全不透明
}

/**
 * 填充像素块
 */
function fillBlock(
  output: Uint8ClampedArray,
  startX: number,
  startY: number,
  size: number,
  width: number,
  height: number,
  color: { r: number; g: number; b: number; a: number }
): void {
  for (let y = startY; y < startY + size && y < height; y++) {
    for (let x = startX; x < startX + size && x < width; x++) {
      const index = (y * width + x) * 4;
      output[index] = color.r;
      output[index + 1] = color.g;
      output[index + 2] = color.b;
      output[index + 3] = color.a;
    }
  }
}

/**
 * 辅助函数：十六进制颜色转RGB
 */
export function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16)
  } : null;
}

/**
 * 辅助函数：计算颜色距离
 */
export function colorDistance(color1: { r: number; g: number; b: number }, color2: { r: number; g: number; b: number }): number {
  return Math.sqrt(
    Math.pow(color2.r - color1.r, 2) +
    Math.pow(color2.g - color1.g, 2) +
    Math.pow(color2.b - color1.b, 2)
  );
}


// // 添加抖动应用函数
// function applyDithering(
//   color: { r: number; g: number; b: number },
//   x: number,
//   y: number,
//   palette?: Palette
// ): { r: number; g: number; b: number } {
//   // 获取 Bayer 矩阵中的阈值 (0-63)
//   const threshold = BAYER_MATRIX_8X8[y % 8][x % 8];
//   // 归一化到 0-1 范围
//   const normalizedThreshold = threshold / 64;

//   // 计算当前颜色的亮度 (使用加权平均值，符合人眼感知)
//   const brightness = (color.r * 0.299 + color.g * 0.587 + color.b * 0.114) / 255;

//   // 如果亮度高于阈值，稍微调亮颜色；否则稍微调暗
//   if (brightness > normalizedThreshold) {
//     // 调亮：增加 RGB 值
//     return {
//       r: Math.min(255, color.r + 15),
//       g: Math.min(255, color.g + 15),
//       b: Math.min(255, color.b + 15)
//     };
//   } else {
//     // 调暗：减少 RGB 值
//     return {
//       r: Math.max(0, color.r - 15),
//       g: Math.max(0, color.g - 15),
//       b: Math.max(0, color.b - 15)
//     };
//   }
// }

// 优化的抖动实现
function applyPixelationEffect(
  data: Uint8ClampedArray,
  width: number,
  height: number,
  params: PixelationParams,
  palette?: Palette
): Uint8ClampedArray {
  const { pixelSize, colorDepth, useDithering } = params;
  const output = new Uint8ClampedArray(data.length);

  for (let y = 0; y < height; y += pixelSize) {
    for (let x = 0; x < width; x += pixelSize) {
      const avgColor = getBlockAverageColor(data, x, y, pixelSize, width, height);
      const limitedColor = limitColorDepth(avgColor, colorDepth);

      let baseColor: { r: number; g: number; b: number; a: number };

      if (palette) {
        baseColor = applyPalette(limitedColor, palette.colors);
      } else {
        baseColor = { ...limitedColor, a: 255 };
      }

      if (useDithering) {
        // 优化的抖动：只在块内关键位置应用抖动，而不是每个像素
        applyOptimizedDithering(output, x, y, pixelSize, width, height, baseColor, palette);
      } else {
        fillBlock(output, x, y, pixelSize, width, height, baseColor);
      }
    }
  }

  return output;
}

// 优化的抖动函数
function applyOptimizedDithering(
  output: Uint8ClampedArray,
  startX: number,
  startY: number,
  size: number,
  width: number,
  height: number,
  baseColor: { r: number; g: number; b: number; a: number },
  palette?: Palette
): void {
  // 在像素块内创建抖动模式
  for (let y = startY; y < startY + size && y < height; y++) {
    for (let x = startX; x < startX + size && x < width; x++) {
      const threshold = BAYER_MATRIX_8X8[y % 8][x % 8] / 64;
      const brightness = (baseColor.r * 0.299 + baseColor.g * 0.587 + baseColor.b * 0.114) / 255;

      let finalColor = baseColor;

      if (brightness > threshold) {
        // 亮色抖动
        finalColor = {
          r: Math.min(255, baseColor.r + 20),
          g: Math.min(255, baseColor.g + 20),
          b: Math.min(255, baseColor.b + 20),
          a: baseColor.a
        };
      } else {
        // 暗色抖动
        finalColor = {
          r: Math.max(0, baseColor.r - 20),
          g: Math.max(0, baseColor.g - 20),
          b: Math.max(0, baseColor.b - 20),
          a: baseColor.a
        };
      }

      // 如果使用了调色板，需要重新映射到调色板颜色
      if (palette) {
        const paletteColor = applyPalette(
          { r: finalColor.r, g: finalColor.g, b: finalColor.b },
          palette.colors
        );
        finalColor = { ...paletteColor, a: baseColor.a };
      }

      const index = (y * width + x) * 4;
      output[index] = finalColor.r;
      output[index + 1] = finalColor.g;
      output[index + 2] = finalColor.b;
      output[index + 3] = finalColor.a;
    }
  }
}
